//
//  NetAPIManager.swift
//  mmda
//
//  Created by 李陆涛 on 2018/4/13.
//  Copyright © 2018年 mmda. All rights reserved.
//

import Foundation
import Moya
import RxSwift
import RxCocoa
import CoreLocation
import DeviceKit


/// 网络请求枚举
///
/// - now: 获取服务器时间戳
/// - first: 客户端初始化信息
/// - code: 手机验证码
/// - checkcode: 验证短信验证码
/// - checklogincode: 自动登录
/// - center: 用户中心
/// - changeprofile: 修改个人资料
/// - qiniutoken: 获取七牛token
/// - notice: 公告接口
/// - suggest: 建议反馈
/// - user: 地图上的用户
/// - alluser: 全部用户
/// - auser: 用户详情
/// - blog: 地图上的动态
/// - allblog: 全部动态
/// - touch: 点赞
/// - blogdetail: 动态详情
/// - comment: 评论
/// - allcomment: 查看全部评论
/// - postBlog: 发送blog
/// - bloghide: 更改blog状态
/// - blogdelete: 删除blog
/// - userhide: 隐藏用户
/// - complaints: 投诉
enum NetAPI {
    //    start
    case now
    case first
    case code(mobile:String)
    case checkcode(mobile:String,code:String)
    case checklogincode(mobile:String,code:String)
    //    user
    case center
    case changeprofile(params:Dictionary<String,Any>?)
    case qiniutoken
    case notice
    case suggest(remark:String)
    
    case user(loc:CLLocationCoordinate2D)
    case alluser(page:Int)
    
    case auser(uid:Int)
    
    //    blog
    case blog(loc:CLLocationCoordinate2D)
    case allblog(uid:Int? ,page:Int)
    
    case touch(bid:Int,status:Int)//status状态 10 ：点赞 , 11 取消点赞
    case blogdetail(bid:Int)
    
    case comment(bid:Int,toUid:Int?,remark:String?)//toUid:是否是回复，如果是回复别人 会有 回复之前的评论 id
    case allcomment(bid:Int,page:Int)
    
    case postBlog(isVideo:Bool,params:[String:Any])
    
    case bloghide(bid:Int,status:Int)//status:0全部可见，11仅自己可见
    
    case blogdelete(bid:Int)
    
    case userhide
    
    case complaints(bid:Int,remark:String,key:String)
}

// 封装网络请求

extension NetAPI: TargetType {
    
    var sampleData: Data {
        
        return "{\"code\":0,\"data\":{\"time\":1523697641,\"secret\":\"c2VjcmV0\"},\"message\":\"success\"}".data(using: .utf8)!
    }
    
    
    var baseURL: URL {
        
        return URL(string: "http://api.mmda.tv/mmda/")!
    }
    
    var path: String {
        
        switch self {
            
        case .now:
            return "start/now"
            
        case .first:
            return "start/first"
            
        case .code:
            return "start/code"
            
        case .checkcode:
            return "start/checkcode"
            
        case .checklogincode:
            return "start/checklogincode"
            
        case .center:
            return "user/center"
            
        case .changeprofile:
            return "user/changeprofile"
            
        case .qiniutoken:
            return "user/qiniutoken"
            
        case .notice :
            
            return "center/notice"
            
        case .blog:
            return "open/blog"
            
        case .user:
            return "open/user"
        case .auser(let uid):
            
            return "user/\(uid)"
            
        case .alluser:
            
            return "user/alluser"
            
        case .allblog(let uid,_):
            
            if let _ = uid {
                
                return "blog/userblog"
            }
            
            return "blog/allblog"
            
        case .touch:
            
            return "praise/touch"
        case .blogdetail(let bid):
            
            return "blog/\(bid)"
        case .comment, .allcomment:
            
            return "comment"
            
        case .suggest:
            
            return "suggest"
        case .postBlog(let isVideo, _):
            
            if isVideo {
                
                return "blog/createvideos"
            }
            
            return "blog"
            
        case .bloghide:
            
            return "blog/hide"
        case .userhide:
            
            return "user/hide"
        case .blogdelete(let bid):
            
            return "blog/\(bid)"
        case .complaints:
            
            return "complaints"
        }
    }
    
    var method: Moya.Method {
        
        switch self {
        case .now, .first, .center, .qiniutoken, .blog, .allblog, .user, .alluser, .auser, .blogdetail, .allcomment, .notice:
            return .get
            
        case .code,.checkcode,.checklogincode,.changeprofile,.touch, .comment, .suggest, .postBlog, .bloghide, .userhide, .complaints:
            return .post
            
        case .blogdelete:
            
            return .delete
        }
        
    }
    
    var task: Task {
        
        switch self {
            
        case .now, .first, .center, .qiniutoken, .notice, .auser, .blogdetail:
            return .requestPlain
            
        case .code(let mobile):
            return .requestParameters(parameters: opParams(["mobile": mobile])!, encoding: JSONEncoding.default)
            
        case .checkcode(let mobile, let code),.checklogincode(let mobile, let code):
            return .requestParameters(parameters: opParams(["mobile": mobile,"code":code])!, encoding: JSONEncoding.default)
            
        case .changeprofile(let params):
            
            guard let params = opParams(params) else {
                
                return .requestPlain
            }
            
            return .requestParameters(parameters:params, encoding: JSONEncoding.default)
            
        case .blog(let loc),.user(let loc):
            
            return .requestParameters(parameters:["longitude":loc.longitude,"latitude":loc.latitude], encoding: URLEncoding.default)
            
        case .allblog(let uid, let page):
            
            var params:[String :Any] = ["page":page,"per-page":kPerPage]
            
            if let uid = uid {
                
                params["user_id"] = uid
            }
            
            return .requestParameters(parameters:opParams(params)!, encoding: URLEncoding.default)
            
        case .alluser(let page):
            
            return .requestParameters(parameters:opParams(["page":page,"per-page":kPerPage])!, encoding: URLEncoding.default)
            
        case .touch(let bid, let status):
            
            return .requestParameters(parameters:opParams(["status":status,"blog_id":bid])!, encoding: JSONEncoding.default)
            
        case .comment(let bid, let toUid, let remark):
            
            
            var params = [String:Any]()
            
            params["blog_id"] = bid
            
            if let toid = toUid {
                
                params["to_comment_id"] = toid
            }
            
            if let remark = remark {
                
                params["remark"] = remark
            }
            
            return .requestParameters(parameters:opParams(params)!, encoding: JSONEncoding.default)
            
        case .allcomment(let bid, let page):
            
            return .requestParameters(parameters:opParams(["blog_id":bid,"page":page,"per-page":kPerPage])!, encoding: URLEncoding.default)
            
        case .userhide:
            
            return .requestParameters(parameters:opParams(nil)!, encoding: JSONEncoding.default)
        case .suggest(let remark):
            
            return .requestParameters(parameters:opParams(["remark":remark])!, encoding: JSONEncoding.default)
        case .postBlog(_, let params):
            
            return .requestParameters(parameters:opParams(params)!, encoding: JSONEncoding.default)
        case .bloghide(let bid, let status):
            
            return .requestParameters(parameters:opParams(["blog_id":bid,"status":status])!, encoding: JSONEncoding.default)
        case .blogdelete:
            
            return .requestParameters(parameters:opParams(nil)!, encoding: JSONEncoding.default)
        case .complaints(let bid, let remark, let key):
            
            return .requestParameters(parameters:opParams(["blog_id":bid,"remark":remark,"key":key])!, encoding: JSONEncoding.default)
        }
        
    }
    
    /// 封装参数，加上必须的位置信息
    ///
    /// - Parameter params: 需要封装的参数
    /// - Returns: 增加位置信息的字典
    func opParams(_ params:Dictionary<String,Any>?) -> Dictionary<String,Any>? {
        
        guard let loc = AppManager.share.cLocation?.coordinate else { return params}
        
        var p = params ?? [:]
        
        p["longitude"] = loc.longitude
        p["latitude"] = loc.latitude
        
        return p
    }
    
    var headers: [String : String]? {
        
        var headers = ["Content-type": "application/json"]
        
        if let platform = AppManager.share.platform {
            
            headers["platform"] = platform
        }
        
        if let unLoginToken = AppManager.share.getUnLoginToken() {
            
            headers["APP-ACCESS-TOKEN"] = unLoginToken
        }
        
        if let token = AppManager.share.token {
            
            headers["X-ACCESS-TOKEN"] = token
        }
        
        return headers
    }
}

let networkActiovtyPlugin = NetworkActivityPlugin { (change, target) in
    
    DispatchQueue.main.async {
        
        switch(change) {
            
        case .ended:
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
            
        case .began:
            
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
        }
    }
}

// 发起请求

let provider = MoyaProvider<NetAPI>(plugins: [NetworkLoggerPlugin(verbose: true),networkActiovtyPlugin])

let disposeBag = DisposeBag()

typealias CompletionBlock = (_ response: Any?,_ errorMsg: String?) -> Void

extension NetAPI {
    
    /// 发起网络请求
    ///
    /// - Parameters:
    ///   - type: 返回数据的model类型
    ///   - dealJson: 处理的json e.g.:"blogs" 会在得到的response中取出blogs的一层去处理
    ///   - completion: 完成block
    func request<T: Codable>(_ type:T.Type, dealJson:String, completion: @escaping CompletionBlock) {
        
        request { (response, errorMsg) in
            
            guard let response = response else {
                
                completion(nil,errorMsg)
                return
            }
            
            do {
                
                let myres = response as? Dictionary<String,Any>
                
                let jsonData = try
                    JSONSerialization.data(
                        withJSONObject:myres?[dealJson] ?? response,
                        options:JSONSerialization.WritingOptions.prettyPrinted)
                
                let decoder = JSONDecoder()
                
                decoder.dateDecodingStrategy = .secondsSince1970
                
                let model = try decoder.decode(type.self, from: jsonData)
                
                completion(model,nil)
                
            } catch {
                
                completion(nil,"初始化失败")
            }
        }
        
    }
    
    
    /// 发起网络请求
    ///
    /// - Parameters:
    ///   - type: 返回数据的model类型
    ///   - completion: 完成block
    func request<T: Codable>(_ type:T.Type, completion: @escaping CompletionBlock) {
        
        
        request { (response, errorMsg) in
            
            guard let response = response else {
                
                completion(nil,errorMsg)
                return
            }
            
            do {
                
                let jsonData = try
                    JSONSerialization.data(
                        withJSONObject:response,
                        options:JSONSerialization.WritingOptions.prettyPrinted)
                
                let decoder = JSONDecoder()
                
                decoder.dateDecodingStrategy = .secondsSince1970
                
                let model = try decoder.decode(type.self, from: jsonData)
                
                completion(model,nil)
                
            } catch {
                
                completion(nil,"初始化失败")
            }
        }
    }
    
    
    /// 发起网络请求
    ///
    /// - Parameter completion: 完成block
    func request(completion: @escaping CompletionBlock) {
        
        provider.rx.request(self).mapJSON().subscribe { event in
            
            switch event {
                
            case .success(let response):
                
                guard let response = response as? Dictionary<String, Any> else {
                    
                    completion(nil,"初始化失败")
                    
                    return
                    
                }
                
                let code = response["code"] as? Int ?? -1
                
                if code == 0 {
                    
                    completion(response["data"],nil)
                    
                    return
                    
                }
                
                completion(nil, response["message"] as? String ?? "初始化失败")
                
            case .error(let error):
                
                completion(nil, error.localizedDescription)
            }
            
            }.disposed(by: disposeBag)
    }
}

import HXPhotoPicker
import Qiniu

extension NetAPI {
    
    /// --
    ///
    /// - Parameters:
    ///   - models: --
    ///   - handler: (是否视频，key数组，错误信息，视频尺寸)
    static func uploadToQN(_ models:[HXPhotoModel],_ handler:@escaping (Bool,[String]?,String?,CGSize?) -> Void) {
        
        NetAPI.qiniutoken.request {
            
            response, errmsg in
            
            guard let response = response as? [String:Any] else {
                
                handler(false,nil,errmsg, nil)
                
                return
            }
            
            guard let token = response["token"] as? String else {
                
                handler(false,nil,"网络加载失败，请稍后重试",nil)
                return
            }
            
            let uploadManager = QNUploadManager.sharedInstance(with: nil)
            
            let model = models.first!
            
            print(model.description)
            
            if model.subType == HXPhotoModelMediaSubTypeVideo {
                
                let second = Int(Date().timeIntervalSince1970 * 1000)
                let random = arc4random() % 1000
                
                let key = "mmdatv\(AppManager.share.user?._id ?? 0)\(second)\(random)\(0).mp4"
                
                
                guard let data = try? Data(contentsOf: model.fileURL) else { return }
                
                uploadManager?.put(data, key: key, token: token, complete: { (info, _, res) in
                    
                    if let info = info,info.statusCode == 200 {
                        
                        
                        DispatchQueue.global().async {
                            
                            let avAsset = AVAsset(url: model.fileURL)
                            
                            var size:CGSize = CGSize(width: kScreenWidth, height: kScreenHeight)
                            
                            if let videoTrack = avAsset.tracks(withMediaType: AVMediaType.video).first {
                                
                                size = CGSize(width: videoTrack.naturalSize.height, height: videoTrack.naturalSize.width)
                            }
                            
                            DispatchQueue.main.async {
                                
                                handler(true,[key],nil,size)
                            }
                        }
                    }
                    
                }, option: nil)
                
                return
            }
            
            let group = DispatchGroup()
            
            var keys = [String]()
            
            for i in 0..<models.count {
                
                let model = models[i]
                
                group.enter()
                
                
                let second = Int(Date().timeIntervalSince1970 * 1000)
                let random = arc4random() % 1000
                
                let type = model.type == HXPhotoModelMediaTypePhotoGif ? "gif":"jpg"
                
                let key = "mmdatv\(AppManager.share.user?._id ?? 0)\(second)\(random)\(i).\(type)"
                
                
                keys.append(key)
                
                if let asset = model.asset {
                    
                    uploadManager?.put(asset, key: key, token: token, complete: { (info, key, res) in
                        
                        if info == nil || info?.statusCode != 200 {
                            
                            keys.remove(at: keys.index(of: key!)!)
                        }
                        
                        group.leave()
                        
                    }, option: nil)
                } else if let image = model.previewPhoto {
                    
                    let data = UIImageJPEGRepresentation(image, 0.5)
                    
                    uploadManager?.put(data, key: key, token: token, complete: { (info, key, res) in
                        
                        if info == nil || info?.statusCode != 200 {
                            
                            keys.remove(at: keys.index(of: key!)!)
                        }
                        
                        group.leave()
                        
                    }, option: nil)
                } else {
                    
                    keys.remove(at: keys.index(of: key)!)
                    group.leave()
                }
            }
            
            group.notify(queue: DispatchQueue.main, execute: {
                
                handler(false,keys,nil,nil)
                
            })
        }
    }
    
}
